#******************************************************************************
#******************************************************************************

# import libraries

from src.hyhetra.common.fluids import Fluid, FluidDatabase

from src.hyhetra.common.formulas import PrandtlNumber, ReynoldsNumber

from src.hyhetra.common.formulas import PrandtlNumber, ReynoldsNumber

from src.hyhetra.common.formulas import MeanFluidSpeedFromReynoldsNumber

from src.hyhetra.common.formulas import ThermalDiffusivity

from src.hyhetra.common.formulas import KinematicViscosity, NusseltNumber

#import numpy as np

from iapws import IAPWS97

from numpy.testing import assert_allclose

#******************************************************************************
#******************************************************************************
#******************************************************************************
#******************************************************************************

def examples(fluiddb: FluidDatabase):
    
    # # fluiddata_file = 'data/fluids/water/incropera2006_saturated_water.csv'

    # # fluiddb = FluidDatabase(fluid='fluid', source=fluiddata_file)
    
    # fluiddata_file = 'data/fluids/water/incropera2006_saturated_water.csv'

    # fluiddb = FluidDatabase(fluid='fluid', phase='l', source=fluiddata_file)
    
    # fluiddb = waterdb
    
    # tests
    
    verify_fluiddatabase(fluiddb)
    
    example_fluid_numbers(fluiddb)
    
    example_fluid_numbers_iapws(fluiddb)
    
    example_fluidobj_creation_direct()
    
    example_fluidobj_creation_via_db(fluiddb)
    
    example_miscellaneous(fluiddb)

#******************************************************************************
#******************************************************************************
#******************************************************************************
#******************************************************************************

def example_miscellaneous(fluiddb: FluidDatabase):
    
    fluid = Fluid(phase='l',
                  temperature=273.15+50,
                  pressure=1e5,
                  db=fluiddb)
    
    
    kinematic_viscosity = KinematicViscosity(fluid.dynamic_viscosity,
                                             fluid.mass_density)
                                                 
    nusselt_number = NusseltNumber(0.05,
                                   3, 
                                   fluid.thermal_conductivity)
    
#******************************************************************************
#******************************************************************************
#******************************************************************************
#******************************************************************************

def verify_fluid_object(fluid):
    
    # check if it has d_int, d_ext, ins_d and sp
    
    assert hasattr(fluid, "phase")
    
    assert hasattr(fluid, "temperature")
    
    assert hasattr(fluid, "pressure")
    
    assert hasattr(fluid, "mass_density")
    
    assert hasattr(fluid, "specific_heat")
    
    assert hasattr(fluid, "dynamic_viscosity")
    
    assert hasattr(fluid, "kinematic_viscosity")
    
    assert hasattr(fluid, "thermal_conductivity")
    
    assert hasattr(fluid, "thermal_diffusivity")
    
    assert hasattr(fluid, "prandtl_number")
    
    assert hasattr(fluid, "coefficient_expansion")
    
    # assert hasattr(fluid, "surface_tension")
    
    # assert hasattr(fluid, "heat_vaporisation")

#******************************************************************************
#******************************************************************************
#******************************************************************************
#******************************************************************************

# test pipe database creation

def verify_fluiddatabase(fluiddb):
    
    # check if attributes exist
    
    # fluid: str     
    # mass_density: dict = field(init=False)
    # specific_heat: dict = field(init=False)
    # dynamic_viscosity: dict = field(init=False)
    # thermal_conductivity: dict = field(init=False)
    # prandtl_number: dict = field(init=False)
    # coefficient_expansion: dict = field(init=False) # no phase distinction   
    # surface_tension: dict = field(init=False)       # no phase distinction
    # heat_vaporisation: dict = field(init=False)     # no phase distinction
    
    assert hasattr(fluiddb, "fluid")
    
    assert hasattr(fluiddb, "mass_density")
    
    assert hasattr(fluiddb, "specific_heat")
    
    assert hasattr(fluiddb, "dynamic_viscosity")
    
    assert hasattr(fluiddb, "kinematic_viscosity")
    
    assert hasattr(fluiddb, "thermal_conductivity")
    
    assert hasattr(fluiddb, "thermal_diffusivity")
    
    assert hasattr(fluiddb, "prandtl_number")
    
    assert hasattr(fluiddb, "coefficient_expansion")
    
    # assert hasattr(fluiddb, "surface_tension")
    
    # assert hasattr(fluiddb, "heat_vaporisation")
    
    # check attribute types
    
    assert type(fluiddb.fluid) == str
    
    assert type(fluiddb.mass_density) == dict
    
    assert type(fluiddb.specific_heat) == dict
    
    assert type(fluiddb.dynamic_viscosity) == dict
    
    assert type(fluiddb.kinematic_viscosity) == dict
    
    assert type(fluiddb.thermal_conductivity) == dict
    
    assert type(fluiddb.thermal_diffusivity) == dict
    
    assert type(fluiddb.prandtl_number) == dict
    
    assert type(fluiddb.coefficient_expansion) == dict
    
    # assert type(fluiddb.surface_tension) == dict
    
    # assert type(fluiddb.heat_vaporisation) == dict

#******************************************************************************
#******************************************************************************
#******************************************************************************
#******************************************************************************

# test creating standardisedpipe class instances using a pipe database

def example_fluidobj_creation_via_db(fluiddb):
    
    temperature = 273.15+50
    
    pressure = 1e5
    
    fluid = Fluid(phase='l',
                  temperature=temperature,
                  pressure=pressure,
                  db=fluiddb)
    
    # verify object
    
    verify_fluid_object(fluid)

#******************************************************************************
#******************************************************************************
#******************************************************************************
#******************************************************************************

# test creating standardisedpipe class instances using a pipe database

def example_fluidobj_creation_direct():
    
    fluid = Fluid(phase='l',
                  temperature=273.15+50,
                  pressure=1e5,
                  mass_density=1000,
                  thermal_conductivity=0.6,
                  dynamic_viscosity=0.4/1000,
                  kinematic_viscosity=4e-7,
                  prandtl_number=3,
                  specific_heat=4180,
                  coefficient_expansion=0)
    
    
    # test object
    
    verify_fluid_object(fluid)

#******************************************************************************
#******************************************************************************
#******************************************************************************
#******************************************************************************

def example_fluid_numbers(fluiddb):
    
    #**************************************************************************
    
    relative_tolerance = 0.01
    
    temperature = 273.15+50
    
    pressure = 1e5
    
    characteristic_length = 0.5 # meters
    
    fluid_speed = 0.1 # meters per second

    re_true = 90444
    
    fluid_speed_true = 0.1
    
    #**************************************************************************
    
    fluid = Fluid(phase='l',
                  temperature=temperature,
                  pressure=pressure,
                  db=fluiddb)
    
    #**************************************************************************
    
    # prandtl number
    
    prandtl_number = PrandtlNumber(fluid.specific_heat,
                                   fluid.dynamic_viscosity,
                                   fluid.thermal_conductivity)
    
    pr_true = fluid.prandtl_number

    pr_tol = pr_true*relative_tolerance
    
    assert prandtl_number <= pr_true+pr_tol
    
    assert prandtl_number >= pr_true-pr_tol
    
    # reynolds number
    
    reynolds_number = ReynoldsNumber(characteristic_length, 
                                     fluid_speed, 
                                     fluid.kinematic_viscosity)

    re_tol = re_true*relative_tolerance
    
    assert reynolds_number <= re_true+re_tol
    
    assert reynolds_number >= re_true-re_tol
    
    # fluid speed
    
    fluid_speed_tol = fluid_speed_true*relative_tolerance
    
    fluid_speed2 = MeanFluidSpeedFromReynoldsNumber(
        characteristic_length,
        reynolds_number,
        fluid.kinematic_viscosity)
    
    assert fluid_speed2 <= fluid_speed_true+fluid_speed_tol
    
    assert fluid_speed2 >= fluid_speed_true-fluid_speed_tol
    
    #**************************************************************************

#******************************************************************************
#******************************************************************************
#******************************************************************************
#******************************************************************************

def example_fluid_numbers_iapws(fluiddb):

    #**************************************************************************
    
    atm_pressure = 101325 # 1 atm
    
    temperature_pressure_tuple_list = [(273.15+0,atm_pressure),
                                       (273.15+25,atm_pressure),
                                       (273.15+50,atm_pressure),
                                       (273.15+75,atm_pressure),
                                       (273.15+100,atm_pressure+100)]
                                       
    # temperature_pressure_tuple_list = [(273.15+0,0.1),
    #                                    (273.15+25,0.1),
    #                                    (273.15+50,0.1),
    #                                    (273.15+75,0.1),
    #                                    (273.15+100,0.1)]
                                       
    relative_tolerance = 0.05
    
    # 1 MPa = 10 bar
    
    MPa2Pa = 1E6
    
    for t_p_tuple in temperature_pressure_tuple_list:

        #**********************************************************************

        temperature = t_p_tuple[0]
        
        pressure = t_p_tuple[1] 
        
        #**********************************************************************
    
        water = IAPWS97(T=temperature,P=pressure/MPa2Pa)
        
        pr_true = water.Prandt
        
        k_true = water.k
        
        cp_true = water.cp*1000
        
        rho_true = water.rho
        
        mu_true = water.mu
        
        nu_true = water.nu
        
        alfa_true = water.alfa
        
        sigma_true = water.sigma
    
        #**********************************************************************
        
        fluid = Fluid(phase='l',
                      temperature=temperature,
                      pressure=pressure,
                      db=fluiddb)
        
        #**********************************************************************
        
        # density
        
        value = fluid.mass_density
        
        value_true = rho_true    
        
        assert_allclose(value, value_true, relative_tolerance)
        
        # specific heat
        
        value = fluid.specific_heat
        
        value_true = cp_true    
        
        assert_allclose(value, value_true, relative_tolerance)
        
        # dynamic viscosity
        
        value = fluid.dynamic_viscosity
        
        value_true = mu_true    
        
        assert_allclose(value, value_true, relative_tolerance)
        
        # kinematic viscosity
        
        value = fluid.kinematic_viscosity
        
        value_true = nu_true    
        
        assert_allclose(value, value_true, relative_tolerance)
        
        # thermal conductivity
        
        value = fluid.thermal_conductivity
        
        value_true = k_true    
        
        assert_allclose(value, value_true, relative_tolerance)
        
        # thermal diffusivity
        
        value = ThermalDiffusivity(fluid.thermal_conductivity,
                                   fluid.mass_density,
                                   fluid.specific_heat)
        
        value_true = alfa_true    
        
        assert_allclose(value, value_true, relative_tolerance)
        
        # prandtl number
        
        value = fluid.prandtl_number
        
        value_true = pr_true    
        
        assert_allclose(value, value_true, relative_tolerance)
        
        # # surface tension
        
        # value = fluid.surface_tension
        
        # value_true = sigma_true
        
        # assert_allclose(value, value_true, relative_tolerance)
        
        #**********************************************************************

#******************************************************************************
#******************************************************************************
#******************************************************************************
#******************************************************************************